package router

import (
	"embed"
	"fmt"
	"io/fs"
	"net/http"
	"strings"
	"time"
	"uap/common"
	"uap/controller"
	"uap/pkg/app"
	"uap/utils"

	"github.com/gin-contrib/cors"
	"github.com/gin-gonic/gin"
)

func InitDynamicRouter(r *gin.Engine) {

	noauth := r.Group("../api")

	userCtl := controller.NewUser()
	noauth.POST("/login", userCtl.Login)

	captcha := controller.NewCaptchaCtl()
	noauth.GET("/captcha", captcha.LoginCaptcha)

	auth := r.Group("../api", auth())
	auth.GET("/getUserInfo", userCtl.GetUserInfo)

	monitor := controller.NewMoniror()
	auth.GET("/monitor", monitor.Query)

	tbApp := controller.NewTbApp()
	auth.GET("/app/list", tbApp.List)
	auth.POST("/app/add", tbApp.Add)
	auth.GET("/app/delete", tbApp.Delete)
	auth.POST("/app/update", tbApp.Update)
	auth.GET("/app/getById", tbApp.GetById)
	auth.GET("/app/getByAppId", tbApp.GetByAppId)

	auth.GET("/user/list", userCtl.List)
	auth.POST("/user/add", userCtl.Add)
	auth.GET("/user/delete", userCtl.Delete)
	auth.POST("/user/update", userCtl.Update)
	auth.GET("/user/getById", userCtl.GetById)
	auth.GET("/user/getCurrentUser", userCtl.GetCurrentUser)

	qrcode := controller.NewQrcode()
	auth.POST("/v1/confirmBefore", qrcode.ScanBeforeOption)
	auth.POST("/v1/confirmAfter", qrcode.ScanAfterOption)

	//开放接口
	noauth.GET("/v1/createLoginQrcode", qrcode.CreateLoginQrcode)
	noauth.GET("/v1/createRegisterQrcode", qrcode.CreateRegisterQrcode)
	noauth.GET("/v1/scanStatus", qrcode.ScanStatus)

	openApi := controller.NewOpenApi()
	noauth.GET("/v1/getUserInfo", openApi.GetUserInfo)
	noauth.POST("/v1/login", openApi.Login)
	auth.POST("/v1/getAppById", openApi.GetAppById)
	// auth.POST("/v1/getAppById", openApi.GetAppById)

}

func auth() gin.HandlerFunc {
	return func(c *gin.Context) {
		token := c.PostForm("token")
		if token == "" {
			token = c.DefaultQuery("token", "")
		}
		if token == "" {
			token = c.Request.Header.Get("token")
		}
		if token == "" {
			c.Abort()
			app.Error(c, app.TokenTimeout.Code, app.TokenTimeout.Msg)
			return
		}
		_, err := utils.GetTokenUser(token)
		if err != nil {
			//token过期
			c.Abort()
			app.Error(c, app.TokenTimeout.Code, app.TokenTimeout.Msg)
			return
		} else {
			c.Next()
		}
	}
}

func InitStaticRouter(r *gin.Engine, embedFrontend embed.FS) {
	r.Use(cors.New(cors.Config{
		AllowOrigins:     []string{"*"},
		AllowMethods:     []string{"GET", "POST", "DELETE", "PUT", "HEAD", "OPTIONS"},
		AllowHeaders:     []string{"Origin", "authorization", "content-type"},
		ExposeHeaders:    []string{"Content-Length"},
		AllowCredentials: true,
		MaxAge:           12 * time.Hour,
	}))

	r.GET("/", func(c *gin.Context) {
		c.Status(http.StatusFound)
		c.Writer.Header().Set("Location", "./dashbord/")
	})

	front, err := fs.Sub(embedFrontend, "web/dist")
	if err != nil {
		fmt.Println(err)
	}

	HTTPCacheForUI(r)
	r.StaticFS("/dashbord/", http.FS(front))

	r.NoRoute(func(c *gin.Context) {
		fmt.Println("=========>c.Request.RequestURI", c.Request.RequestURI)
		if strings.HasPrefix(c.Request.RequestURI, "/dashbord/") {
			path := strings.TrimPrefix(c.Request.RequestURI, "/dashbord/")
			locationPath := strings.Repeat("../", strings.Count(path, "/"))
			c.Status(http.StatusFound)
			c.Writer.Header().Set("Location", "./"+locationPath)
		}
	})
}

func HTTPCacheForUI(app *gin.Engine) {
	app.Use(func(c *gin.Context) {
		if c.Request.Method == "GET" || c.Request.Method == "HEAD" {
			if strings.Contains(c.Request.RequestURI, "/dashbord/static/") {
				c.Writer.Header().Set("cache-control", "public, max-age=2592000")
				c.Writer.Header().Set("expires", time.Now().Add(time.Hour*24*30).Format(time.RFC1123))
				if strings.Contains(c.Request.RequestURI, ".js") {
					c.Writer.Header().Set("content-type", "application/javascript")
				}
				if strings.Contains(c.Request.RequestURI, ".css") {
					c.Writer.Header().Set("content-type", "text/css; charset=utf-8")
				}
			}
		}
		c.Next()
	})
}

func Cors() gin.HandlerFunc {
	return func(c *gin.Context) {
		method := c.Request.Method
		origin := c.Request.Header.Get("Origin") //请求头部
		if origin != "" {
			//接收客户端发送的origin （重要！）
			//Access-Control-Allow-Origin是必须的,他的值要么是请求Origin字段的值,要么是一个*, 表示接受任意域名的请求
			c.Writer.Header().Set("Access-Control-Allow-Origin", "*")
			//服务器支持的所有跨域请求的方法
			c.Header("Access-Control-Allow-Methods", "POST, GET, OPTIONS, PUT, DELETE,UPDATE")
			//允许跨域设置可以返回其他子段，可以自定义字段
			//该字段可选。CORS请求时，XMLHttpRequest对象的getResponseHeader()方法只能拿到6个基本字段：Cache-Control、Content-Language、Content-Type、Expires、Last-Modified、Pragma。
			//如果想拿到其他字段，就必须在Access-Control-Expose-Headers里面指定。上面的例子指定，getResponseHeader('FooBar')可以返回FooBar字段的值。
			c.Header("Access-Control-Allow-Headers", "Authorization, Content-Length, X-CSRF-Token, Token, session")
			// 允许浏览器（客户端）可以解析的头部 （重要）
			c.Header("Access-Control-Expose-Headers", "Content-Length, Access-Control-Allow-Origin, Access-Control-Allow-Headers")
			//设置缓存时间
			//该字段可选，用来指定本次预检请求的有效期，单位为秒。有效期是20天（1728000秒），即允许缓存该条回应1728000秒（即20天），在此期间，不用发出另一条预检请求。
			c.Header("Access-Control-Max-Age", "172800")
			//允许客户端传递校验信息比如 cookie (重要)
			c.Header("Access-Control-Allow-Credentials", "true")
		}
		//允许类型校验
		if method == "OPTIONS" {
			c.JSON(http.StatusOK, "ok!")
		}
		defer func() {
			if err := recover(); err != nil {
				fmt.Println(err)
			}
		}()
		c.Next()
	}
}

func ArgsFilter() gin.HandlerFunc {
	return func(c *gin.Context) {
		table := c.DefaultQuery("table", "")
		if len(table) > 0 && !common.VerifyArgs.MatchString(table) {
			app.Error(c, app.ParamsError.Code, app.ParamsError.Msg)
			return
		}
		chain := c.DefaultQuery("chain", "")
		if len(chain) > 0 && !common.VerifyArgs.MatchString(chain) {
			app.Error(c, app.ParamsError.Code, app.ParamsError.Msg)
			return
		}
		c.Next()
	}
}
